package com.zzw.zim.security.config;

import com.zzw.zim.security.access.InServiceAccess;
import com.zzw.zim.security.access.InServiceAccessImpl;
import com.zzw.zim.security.exception.SecurityAuthenticationEntryPoint;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * Security过滤器链配置
 *
 * @author XiaoJie
 * @date 2025/5/15 14:07
 */
@Configuration
@AllArgsConstructor
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityFilterConfig {
	private final OncePerRequestFilter authenticationTokenFilter;
	private final PermitResource permitResource;
	private final HttpServletRequest request;


	@Bean
	public InServiceAccess inServiceAccess () {
		return new InServiceAccessImpl(request);
	}

	@Bean
	SecurityFilterChain securityFilterChain (HttpSecurity http) throws Exception {
		// 忽略授权的地址列表
		List<String> permitList = permitResource.getPermitList();
		String[] permits = permitList.toArray(new String[0]);

		//开启会话管理配置
		http.sessionManagement()
				//将会话创建策略设置为无状态，即不使用 HTTP 会话来管理用户认证状态
				.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
				//返回到 HttpSecurity 对象，以便继续配置其他安全规则。
				.and()
				//开启请求授权配置
				.authorizeRequests()
				//匹配以 /sse/ 开头的所有路径和/system/login
				.antMatchers("/sse/**","/system/auth/login","/business/file/getDownload/**")
				//允许所有用户访问这些路径，无需认证
				.permitAll()
				//匹配忽略授权地址列表中的路径。
				.antMatchers(permits)
				//允许所有用户访问这些路径，无需认证。
				.permitAll()
				//匹配剩余所有请求路径
				.antMatchers("/**")
				//只有当 InServiceAccess Bean 的 isService() 方法返回 true 时，才允许访问所有路径
				.access("@inServiceAccess.isService()")
				//匹配所有 OPTIONS 请求方法。
				.antMatchers(HttpMethod.OPTIONS)
				.permitAll()
				//匹配其他所有未匹配的请求。
				.anyRequest()
				.authenticated()
				.and()
				//开启异常处理配置
				.exceptionHandling()
				//设置认证入口点，当用户未认证就访问需要认证的资源时，会调用 SecurityAuthenticationEntryPoint 类来处理。
				.authenticationEntryPoint(new SecurityAuthenticationEntryPoint())
				.and()
				//：开启响应头配置
				.headers()
				//禁用 X-Frame-Options 头，允许页面在 iframe 中显示
				.frameOptions()
				.disable()
				.and()
				//在 UsernamePasswordAuthenticationFilter 过滤器之前添加自定义的 authenticationTokenFilter 过滤器，用于处理认证令牌。
				.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
				//csrf().disable()：禁用跨站请求伪造（CSRF）保护
				.csrf()
				.disable();
        //调用 http.build() 方法构建并返回配置好的 SecurityFilterChain 对象。
		return http.build();
	}

}
